package com.ys.web.pay.service;

import cn.hutool.core.util.IdUtil;
import com.ys.base.BaseParam;
import com.ys.utils.base.j2se.DateUtil;
import com.ys.utils.base.j2se.JsonUtil;
import com.ys.utils.base.j2se.Logger;
import com.ys.utils.base.j2se.StringHandler;
import com.ys.utils.pay.Result;
import com.ys.utils.redis.Redis;
import com.ys.utils.spring.config.SystemError;
import com.ys.web.pay.PayEnum;
import com.ys.web.pay.RedisKeyToYs;
import com.ys.web.pay.manager.PayManager;
import com.ys.web.pay.mapper.TransferMapper;
import com.ys.web.pay.model.BusiTransferRecordCash;
import com.ys.web.sys.notice.service.NoticeService;
import com.ys.web.sys.notice.vo.SystemNoticeVo;
import com.ys.web.yinsheng.model.RequestData;
import com.ys.web.yinsheng.model.UserMerchant;
import com.ys.web.yinsheng.service.YinShengService;
import com.ys.web.yinsheng.util.ServiceEnum;
import com.ys.web.yinsheng.util.YinShengClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class TransferService {
    @Value("${ys.default.head_img}")
    private String DEFAULT_IMG;

    // 转账过期时间 24小时
    private final int expireTime = 60 * 60 * 23;

    @Autowired
    private TransferMapper transferMapper;
    @Autowired
    private NoticeService noticeService;
    @Autowired
    private YinShengService yinShengService;

    public BusiTransferRecordCash getBusiTransferRecordCashById(Long id){return transferMapper.getBusiTransferRecordCashById(id);}

    @Transactional
    public Result<Map<String, String>> giveTransfer(String amount, String giveUsers, String userId, String content,String gp,String groupId, String payType,int payChannel) {
        Long redId;
        String messageId = IdUtil.randomUUID().toUpperCase();
        Map<String, String> map = new HashMap<>();
        Result<?> result = null;
        if(payChannel==3){
            // 修改用户账户
            result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_TRANSFER_SEND, Long.parseLong(amount),
                    StringHandler.getString(giveUsers));
        }else if(payChannel==5){
            result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_TRANSFER_SEND, Long.parseLong(amount),
                    StringHandler.getString(giveUsers));
        }else{
            result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_TRANSFER_SEND, Long.parseLong(amount),
                    StringHandler.getString(giveUsers),payChannel);
        }
        if (!result.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.newFailure(-1, result.getMessage());
        }
        // 保存转账信息
        redId = saveBusiTransferRecord(Integer.parseInt(PayEnum.RedPackageStatus.Processing.getCode()),
                gp, amount, giveUsers, userId, content, groupId,payType,payChannel);
        if (StringHandler.isEmpty(redId)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.newFailure(-1, "保存失败，事务回滚");
        }
        // 转账信息记入缓存
        saveTransferCache(redId+"", giveUsers, amount);
        // 返回转账id
        map.put("redId", redId+"");
        map.put("messageId", messageId);
        return Result.newSuccess(map);
    }

    private Long saveBusiTransferRecord(int status, String redType, String redAmount, String giveUsers, String userId, String content,
                                        String groupName, String payType,int payChannel) {
        BusiTransferRecordCash recordCash = new BusiTransferRecordCash();
        recordCash.setUserId(Long.parseLong(userId));
        recordCash.setType(Integer.parseInt(redType));
        recordCash.setStatus(status);
        recordCash.setAmount(Long.parseLong(redAmount));
        recordCash.setListUserId(giveUsers);
        recordCash.setContent(content);
        recordCash.setGroupName(groupName);
        recordCash.setGp(StringHandler.isEmpty(groupName)?1:2);
        recordCash.setPayType(Integer.parseInt(payType));
        recordCash.setDateKey(StringHandler.getInt(com.ys.utils.base.j2se.DateUtil.getYYMMDD()));
        recordCash.setMonthKey(StringHandler.getInt(com.ys.utils.base.j2se.DateUtil.getYYMM()));
        recordCash.payChannel=payChannel;
        transferMapper.saveBusiTransferRecord(recordCash);
        return recordCash.getId();
    }

    private Result<?> saveTransferCache(String redId, String giveUsers, String redAmount) {
        String key = null;
        try {
            Redis.str.set(RedisKeyToYs.REDIS_TRANSFER_PREFIX + redId, String.valueOf(redId), expireTime);
            key = RedisKeyToYs.REDIS_TRANSFER_SINGLE_PREFIX + redId + "-" + giveUsers;
            Redis.str.set(key, redAmount);
        } catch (Exception e) {
            e.printStackTrace();
            clearCache(RedisKeyToYs.REDIS_TRANSFER_PREFIX + redId, key, null, null);
            return Result.newFailure(-1, "缓存保存异常");
        }
        return Result.newSuccess();
    }

    @Transactional
    public Result<Map<String, String>> getTransferPackage(String redId, BusiTransferRecordCash recordCash, String userId,UserMerchant inUser) {
        String amount = "";// 抢转账金额
        // 抢转账
        String key = RedisKeyToYs.REDIS_TRANSFER_SINGLE_PREFIX + redId + "-" + recordCash.listUserId;
        amount = String.valueOf(recordCash.getAmount());

        // 修改转账状态
        recordCash.setStatus(Integer.parseInt(PayEnum.RedPackageStatus.Complete.getCode()));
        Result<BusiTransferRecordCash> redRecordResult = updateBusiTransferRecord(recordCash);
        if (!redRecordResult.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.newFailure(-1, redRecordResult.getMessage());
        }
        Result<?> result = null;
        if(recordCash.payChannel==3) {
            // 修改用户账户
            result = PayManager.accountModifyZfb(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_TRANSFER_RECV,
                    Long.parseLong(amount),
                    StringHandler.getString(recordCash.getUserId()));
        }else if(recordCash.payChannel==5){
            result = PayManager.accountModifyHjzf(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_TRANSFER_RECV,
                    Long.parseLong(amount),
                    StringHandler.getString(recordCash.getUserId()));
        }else{
            // 修改用户账户
            result = PayManager.accountModify(Long.parseLong(userId), PayEnum.AccountFlowType.TYPE_TRANSFER_RECV,
                    Long.parseLong(amount),
                    StringHandler.getString(recordCash.getUserId()),recordCash.payChannel);
        }

        if (!result.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return Result.newFailure(-1, result.getMessage());
        }
        if(recordCash.payChannel<3) {
            //自己抢自己不做转账处理
            if (inUser.uid != recordCash.getUserId()) {
                // 银盛内部转账逻辑将抢转账金额转入抢红包用户钱包
                // 失败回滚事务，直接return
                //查询发送人钱包信息 redRecord.getUserId()
                UserMerchant outUser = yinShengService.userMerchant(recordCash.getUserId() + "");
                // 组装业务参数
                Map<String, Object> requestMap1 = new HashMap<>();
                String requestNo = BaseParam.getOrderSN();
                requestMap1.put("requestNo", requestNo);
                requestMap1.put("payeeMerchantNo", inUser.merchantNo);//收款方银盛商户号
                requestMap1.put("payerMerchantNo", outUser.merchantNo);//付款方银盛商户号
                requestMap1.put("transferType", "C2C");//转账类型 P2B-平台转商户 P2C-平台转用户 B2P-商户转平台 B2B-商户转商户 B2C-商户转用户 C2C-用户转用户 A2A-资金归集
                requestMap1.put("orderDesc", "转账");//商品名称/订单标题
                requestMap1.put("amount", StringHandler.fenToYuan(amount));//提现金额，单位：元
                requestMap1.put("remark", "T-转账");
                RequestData requestData = new RequestData(requestMap1);
                YinShengClient yinShengClient = new YinShengClient(ServiceEnum.TRANSFER_INNER);
                String callback1 = yinShengClient.requestStrApi(requestData);
                Map<String, Object> obj1 = JsonUtil.jsonToBean(callback1, Map.class);
                if (!obj1.get("code").equals("SYS000")) {
                    log.error("T-转账失败:" + StringHandler.getString(obj1.get("msg")),JsonUtil.toJson(recordCash),new Exception());
                    SystemError.wrapBs("500", "转账失败");
                } else {
                    if (StringHandler.isNotEmpty(obj1.get("bizResponseJson"))) {
                        Map<String, Object> bizResponseJson1 = JsonUtil.jsonNullToBean(JsonUtil.toJson(obj1.get("bizResponseJson")), Map.class);
                        if (!bizResponseJson1.get("subCode").equals("COM000")) {
                            log.error("T-转账失败:" + StringHandler.getString(obj1.get("msg")) + "_" + StringHandler.getString(bizResponseJson1.get("subMsg")),JsonUtil.toJson(recordCash),new Exception());
                            SystemError.wrapBs("500", "转账失败");
                        }
                    } else {
                        log.error("T-转账失败:" + StringHandler.getString(obj1.get("msg")),JsonUtil.toJson(recordCash),new Exception());
                        SystemError.wrapBs("500", "转账失败");
                    }
                }
            }
        }
        // 清除缓存
        String redKey = RedisKeyToYs.REDIS_TRANSFER_PREFIX + redId;
        clearCache(redKey, key, null, null);
        Map<String, String> map = new HashMap<>();
        map.put("amount", amount);
        return Result.newSuccess(map);
    }

    public Result<BusiTransferRecordCash> updateBusiTransferRecord(BusiTransferRecordCash redRecord) {
        return transferMapper.updateBusiTransferRecordCash(redRecord)==1 ? Result.newSuccess(redRecord) : Result.newFailure(-1, "失败");
    }

    @Transactional
    public Result<BusiTransferRecordCash> refuseBusiTransferRecord(BusiTransferRecordCash redRecord) {
        Result<?> result = null;
        if(redRecord.payChannel==3){
            // 修改用户账户
            result = PayManager.accountModifyZfb(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_TRANSFER_EXPR,
                    redRecord.getAmount(),
                    redRecord.getListUserId());
        }else if(redRecord.payChannel==5){
            // 修改用户账户
            result = PayManager.accountModifyHjzf(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_TRANSFER_EXPR,
                    redRecord.getAmount(),
                    redRecord.getListUserId());
        }else{
            // 修改用户账户
            result = PayManager.accountModify(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_TRANSFER_EXPR,
                    redRecord.getAmount(),
                    redRecord.getListUserId(),redRecord.payChannel);
        }
        int i = 0;
        if (result.success()) {
            i = transferMapper.updateBusiTransferRecordCash(redRecord);
        }
        if(i==0){
            SystemError.wrapBs("400","退还失败!");
        }
        return i==1 ? Result.newSuccess(redRecord) : Result.newFailure(-1, "失败");
    }

    public void transferGoBack() {
        Logger.info("========================转账定时处理开始========================");
        Date addTime = com.ys.utils.base.j2se.DateUtil.getHourAfterTime(-23);
        Map<String, Object> map = new HashMap<>();
        map.put("EQ_status", PayEnum.RedPackageStatus.Processing.getCode());
        map.put("addTime", com.ys.utils.base.j2se.DateUtil.getDate(addTime,"yyyy-MM-dd HH:mm:ss"));
        List<BusiTransferRecordCash> redRecords = transferMapper.getBusiTransferRecordCashList(map);
        if (StringHandler.isEmpty(redRecords)) {// 没有进行中转账
            Logger.info("========================没有进行中转账========================");
            return;
        }
        for (BusiTransferRecordCash redRecord : redRecords) {
            Long redId = redRecord.getId();
//            if (redRecord.getRawAddTime().after(addTime)) {// 红包未过期
//                log.info("========================红包未过期========================");
//                continue;
//            }
//            if (Redis.key.exists(RedisKeyToYs.REDIS_TRANSFER_PREFIX + redId)) {// 转账未过期
//                log.info("========================转账未过期========================");
//                continue;
//            }
            Logger.info("========================转账过期处理========================" + redId);
            // 转账过期，退回转账
            this.goBackTransfer(redRecord);
        }
        Logger.info("========================转账定时处理结束========================");
    }

    @Transactional
    public void goBackTransfer(BusiTransferRecordCash redRecord) {
        // 更新转账状态为过期
        redRecord.setStatus(Integer.parseInt(PayEnum.RedPackageStatus.Expire.getCode()));
        int i = transferMapper.updateBusiTransferRecordCash(redRecord);
        if (i!=1) {
            return;
        }
        // 修改用户账户
        Result<?> result = null;
        if(redRecord.payChannel==3){
            result = PayManager.accountModifyZfb(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_TRANSFER_EXPR,
                    redRecord.getAmount(),
                    StringHandler.getString(redRecord.getListUserId()));
        }else if(redRecord.payChannel==5){
            result = PayManager.accountModifyHjzf(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_TRANSFER_EXPR,
                    redRecord.getAmount(),
                    StringHandler.getString(redRecord.getListUserId()));
        }else{
            result = PayManager.accountModify(redRecord.getUserId(), PayEnum.AccountFlowType.TYPE_TRANSFER_EXPR,
                    redRecord.getAmount(),
                    StringHandler.getString(redRecord.getListUserId()),redRecord.payChannel);
        }

        if (!result.success()) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return;
        }
        String key = RedisKeyToYs.REDIS_TRANSFER_SINGLE_PREFIX + redRecord.getId() + "-" + redRecord.getListUserId();
        clearCache(null, key, null,null);
        // TODO 转账退还推送
        noticeService.sendOverdueBackNotice(SystemNoticeVo
                .build("转账退还通知",String.format("<p>您有一笔转账已过期退还</p>" +
                                "<p>退还金额：%s元</p>" +
                                "<p>转账时间：%s</p>",
                        StringHandler.fenToYuan(StringHandler.getString(redRecord.getAmount())),
                        DateUtil.getDate(redRecord.getRawAddTime(),"yyyy-MM-dd HH:mm:ss")),
                        redRecord.getUserId()));
    }

    // 红包发完、退回清除红包缓存
    private void clearCache(String... keys) {
        for (String key : keys) {
            if (StringHandler.isNotEmpty(key)) {
                Redis.key.del(key);
            }
        }
    }

    public int transNum(long uid) {
        return transferMapper.transNum(uid);
    }
}
